package com.ibeeking.found.upms.cs.rest.service.impl;

import com.ibeeking.found.common.base.BaseDO;
import com.ibeeking.found.common.config.feign.GlobalClient;
import com.ibeeking.found.common.config.feign.MsgFeignClient;
import com.ibeeking.found.common.config.prop.FileOssProp;
import com.ibeeking.found.common.config.secret.RsaConfig;
import com.ibeeking.found.common.constants.HeaderNounConstant;
import com.ibeeking.found.common.entity.LoginUserDTO;
import com.ibeeking.found.common.entity.TenantDTO;
import com.ibeeking.found.common.entity.UserInfoDTO;
import com.ibeeking.found.common.enums.LoginRoleEnum;
import com.ibeeking.found.common.enums.PublishStatusEnum;
import com.ibeeking.found.common.enums.member.MemberSexEnum;
import com.ibeeking.found.common.utils.UrlUtils;
import com.ibeeking.found.common.utils.UserUtils;
import com.ibeeking.found.upms.api.common.dto.ProjectDTO;
import com.ibeeking.found.upms.api.common.query.AccountLoginQuery;
import com.ibeeking.found.upms.api.feign.SystemProjectClient;
import com.ibeeking.found.upms.cs.rest.config.prop.UserConfigProp;
import com.ibeeking.found.upms.cs.rest.service.ICsUserService;
import com.ibeeking.found.upms.service.common.bo.CsUserBO;
import com.ibeeking.found.upms.service.common.dos.CsUserDO;
import com.ibeeking.found.upms.service.common.param.CsUserParam;
import com.ibeeking.found.upms.service.common.param.ModifyMobileParam;
import com.ibeeking.found.upms.service.common.param.UserFindPwdParam;
import com.ibeeking.found.upms.service.common.param.UserModifyPwdParam;
import com.ibeeking.found.upms.service.common.po.CsUserPO;
import com.ibeeking.found.upms.service.common.query.CsUserPageQuery;
import com.ibeeking.found.upms.service.common.vo.CsUserPageVO;
import com.ibeeking.found.upms.service.common.vo.CsUserVO;
import com.ibeeking.found.upms.service.mapper.CsUserMapper;
import com.ibeeking.nematos.core.utils.SpringBeanUtil;
import com.ibeeking.nematos.exception.BusinessException;
import com.ibeeking.nematos.exception.EncryptException;
import com.ibeeking.nematos.utils.bean.BeanUtil;
import com.ibeeking.nematos.utils.data.Collections3;
import com.ibeeking.nematos.utils.data.StringUtils;
import com.ibeeking.nematos.utils.encryption.EncryptUtils;
import com.ibeeking.nematos.utils.json.JsonUtils;
import com.ibeeking.nematos.utils.result.ResponseResult;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * @ClassName CsUserServiceImpl
 * @Description 全局用户
 * @Author ibeeking
 * @Date 2020-12-01 18:36
 **/
@Service
public class CsUserServiceImpl implements ICsUserService {

    @Resource
    private CsUserMapper csUserMapper;
    @Resource
    private FileOssProp fileOssProp;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Resource
    private MsgFeignClient msgClient;
    @Resource
    private UserConfigProp userConfigProp;
    @Resource
    private RsaConfig rsaConfig;
    @Resource
    private GlobalClient globalClient;
    @Resource
    private SystemProjectClient systemProjectClient;

    @Override
    public Page<CsUserPageVO> pageList(CsUserPageQuery query) {
        LambdaQueryWrapper<CsUserDO> queryWrapper = new LambdaQueryWrapper<>(CsUserDO.class);
        queryWrapper.orderByDesc(BaseDO::getCreateTime)
                .eq(null != query.getPublishStatus(), CsUserDO::getPublishStatus, query.getPublishStatus())
                .eq(null != query.getSex(), CsUserDO::getSex, query.getSex())
                .eq(null != query.getJob(), CsUserDO::getJob, query.getJob())
                .like(StringUtils.isNotBlank(query.getName()), CsUserDO::getName, query.getName())
                .like(StringUtils.isNotBlank(query.getMobile()), CsUserDO::getMobile, query.getMobile())
                .like(StringUtils.isNotBlank(query.getTel()), CsUserDO::getTel, query.getTel())
                .like(StringUtils.isNotBlank(query.getEmail()), CsUserDO::getEmail, query.getEmail())
        ;

        Page<CsUserDO> page = csUserMapper.selectPage(new Page<>(query.getPageNum(), query.getPageSize()), queryWrapper);
        Page<CsUserPageVO> result = BeanUtil.convertPage(page, CsUserPageVO.class);
        Optional.ofNullable(result.getRecords()).ifPresent(list -> {
            list.stream().forEach(userPageVO -> {
                userPageVO.setSexName(MemberSexEnum.getDescByCode(userPageVO.getSex()));
                Optional.ofNullable(userPageVO.getImage()).ifPresent(image -> {
                    userPageVO.setImage(fileOssProp.getHost().concat(userPageVO.getImage()));
                });
            });
        });
        return result;
    }

    @Override
    public String queryTenantLogo() {
        ResponseResult<ProjectDTO> responseResult = systemProjectClient.queryProjectInfo();
        if (null == responseResult || null == responseResult.getData() || StringUtils.isBlank(responseResult.getData().getLogo())) {
            return "";
        }
        return responseResult.getData().getLogo();
    }

    @Override
    public Boolean modifySelf(CsUserParam param) {
        CsUserDO userDO = BeanUtil.convertBean(param, CsUserDO.class);
        userDO.setUserCode(null);
        userDO.setMobile(null);
        userDO.setPassword(null);
        userDO.setModifyBy(UserUtils.getUserId());
        userDO.setModifyTime(LocalDateTime.now());
        return csUserMapper.updateById(userDO) > 0;
    }

    @Override
    public CsUserVO view(Long id) {
        CsUserBO userBO = getBean().queryById(id);
        return BeanUtil.convertBean(userBO, CsUserVO.class);
    }

    @Override
    public CsUserBO queryById(Long id) {
        CsUserDO userDO = csUserMapper.selectById(id);
        userDO.setImage(UrlUtils.addUrlDomainName(fileOssProp.getHost(), userDO.getImage()));
        return JsonUtils.fromJson(userDO, CsUserBO.class);
    }

    @Override
    public Boolean modifyPwd(Long userId, UserModifyPwdParam userModifyPwdParam) {
        CsUserBO userBO = getBean().queryById(userId);
        String oldPwd;
        String newPwd;
        try {
            oldPwd = EncryptUtils.RsaEncrypt.decrypt(userModifyPwdParam.getOldPassword(), rsaConfig.getKeyPair().getPrivate());
            newPwd = EncryptUtils.RsaEncrypt.decrypt(userModifyPwdParam.getNewPassword(), rsaConfig.getKeyPair().getPrivate());
        } catch (Exception e) {
            throw new EncryptException("密码非用户输入密码");
        }
        if (!passwordEncoder.matches(oldPwd, userBO.getPassword())) {
            throw new BusinessException("旧密码错误");
        }
        return getBean().modifyPassword(userId, newPwd);
    }

    @Override
    public Boolean modifyPassword(Long userId, String newPassword) {
        CsUserDO userDO = new CsUserDO();
        userDO.setId(userId);
        userDO.setModifyTime(LocalDateTime.now());
        userDO.setPassword(StringUtils.isEmpty(newPassword) ? passwordEncoder.encode(userConfigProp.getInitialPwd()) : passwordEncoder.encode(newPassword));
        return csUserMapper.updateById(userDO) > 0;
    }

    @Override
    public Boolean findPwd(UserFindPwdParam userFindPwdParam) {
        CsUserDO userDO = csUserMapper.selectOne(new LambdaQueryWrapper<>(CsUserDO.class)
                .eq(CsUserDO::getPublishStatus, PublishStatusEnum.ENABLE.getValue())
                .eq(CsUserDO::getJob, PublishStatusEnum.ENABLE.getValue())
                .eq(CsUserDO::getMobile, userFindPwdParam.getPhone()));
        if (null == userDO) {
            throw new BusinessException("用户不存在");
        }
        ResponseResult<Boolean> responseResult = msgClient.checkVerificationCode(userFindPwdParam.getKey(),userFindPwdParam.getPhone(), userFindPwdParam.getVerificationCode());
        if (null == responseResult || !responseResult.getData()) {
            throw new BusinessException("验证码错误或已过期");
        }
        String newPwd;
        try {
            newPwd = EncryptUtils.RsaEncrypt.decrypt(userFindPwdParam.getNewPassword(), rsaConfig.getKeyPair().getPrivate());
        } catch (Exception e) {
            throw new EncryptException("密码非用户输入密码");
        }
        return getBean().modifyPassword(userDO.getId(), newPwd);
    }

    @Override
    public LoginUserDTO queryAccountLogin(AccountLoginQuery query) {
        //查询所有租户id
        ResponseResult<List<Integer>> responseResult = globalClient.queryTenantIds();
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            return null;
        }
        CsUserPO csUserPO = csUserMapper.queryAccountLogin(responseResult.getData(), query.getMobile());
        if (null == csUserPO) {
            return null;
        }
        LoginUserDTO result = BeanUtil.convertBean(csUserPO, LoginUserDTO.class);
        Integer tenantId= csUserPO.getTenantId();
        if(tenantId!=null) {
            TenantDTO tenantDTO = queryTenantById(tenantId);
            if(tenantDTO != null){
                result.setIndustry(tenantDTO.getIndustry());
            }
        }
        result.setLock(!PublishStatusEnum.ENABLE.getValue().equals(csUserPO.getPublishStatus()));
        result.setJob(PublishStatusEnum.ENABLE.getValue().equals(csUserPO.getJob()));
        result.setLoginRole(LoginRoleEnum.CUSTOMER_SERVICE.name());
        return result;
    }

    @Override
    public UserInfoDTO queryLoginUser(HttpServletRequest request, Long userId) {
        CsUserBO userBO = getBean().queryById(userId);
        if (null == userBO) {
            return null;
        }
        Integer tenantId= Integer.valueOf(request.getHeader(HeaderNounConstant.TENANT_ID));
        UserInfoDTO userInfoDTO = BeanUtil.convertBean(userBO, UserInfoDTO.class);
        userInfoDTO.setTenantId(tenantId);
        if(tenantId!=null) {
            TenantDTO tenantDTO = queryTenantById(tenantId);
            if(tenantDTO != null){
                userInfoDTO.setIndustry(tenantDTO.getIndustry());
            }
        }
        return userInfoDTO;
    }

    @Override
    public Boolean modifyMobile(Long userId, ModifyMobileParam param) {
        ResponseResult<Boolean> responseResult = msgClient.checkVerificationCode(param.getKey(),param.getMobile(), param.getVerificationCode());
        if (null == responseResult || null == responseResult.getData() || !responseResult.getData()) {
            throw new BusinessException("验证码错误或已过期");
        }
        CsUserDO userDO = new CsUserDO();
        userDO.setId(userId);
        userDO.setMobile(param.getMobile());
        userDO.setModifyTime(LocalDateTime.now());
        return csUserMapper.updateById(userDO) > 0;
    }

    private void checkUnique(String mobile, Long id) {
        //查询所有租户id
        ResponseResult<List<Integer>> responseResult = globalClient.queryTenantIds();
        if (null == responseResult || Collections3.isEmpty(responseResult.getData())) {
            throw new BusinessException("请检查是否有租户");
        }
        //手机号邮箱全局校验
        List<Long> ids = csUserMapper.checkUnique(responseResult.getData(), mobile);
        if (!Collections3.isEmpty(ids)) {
            if (null == id) {
                throw new BusinessException("请检查手机号是否重复");
            } else {
                if (1 != ids.size() || !ids.contains(id)) {
                    throw new BusinessException("请检查手机号是否重复");
                }
            }
        }

    }
    private TenantDTO queryTenantById(Integer tenantId) {
        ResponseResult<TenantDTO> responseResult = globalClient.queryTenantById(tenantId);
        if (null == responseResult || null == responseResult.getData()) {
            throw new BusinessException("租户不存在");
        }
        return responseResult.getData();
    }
    private ICsUserService getBean() {
        return SpringBeanUtil.getBean(ICsUserService.class);
    }
}
